package com.why.simpleboot.core.boot.starter;

import com.why.simpleboot.core.configration.ConfigurationFactory;
import com.why.simpleboot.core.configration.DefaultTomcatConfiguration;
import com.why.simpleboot.core.configration.SimpleBootConfiguration;
import com.why.simpleboot.core.server.tomcat.mvc.DispatcherServlet;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.servlets.DefaultServlet;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.StandardRoot;
import org.apache.jasper.servlet.JspServlet;

import java.io.File;
import java.net.URISyntaxException;
import java.nio.file.Files;

/**
 * @program: why-simpleboot-framework
 * @description:制作一个Tomcat的starter
 * @author: @why
 * @create: 2021-07-03 18:59
 **/
public class SimpleBootTomcatStarter extends AbstractSimpleBootStarter {
    private static final Tomcat tomcat = new Tomcat();
    private static final DefaultTomcatConfiguration DEFAULT_TOMCAT_CONFIGURATION = new DefaultTomcatConfiguration();


    public SimpleBootTomcatStarter() {
        init();
    }

    /**
     * 初始化tomcat服务
     */
    private void init() {
        SimpleBootConfiguration configuration = ConfigurationFactory.getConfig();
        try {

            tomcat.setBaseDir(DEFAULT_TOMCAT_CONFIGURATION.getDocBase());
            Integer port = configuration.getInt("port");
            if (port == null) {
                port = 8080;
            }
            tomcat.setPort(port);

            File root = getRootFolder();
            File webContentFolder = new File(root.getAbsolutePath(), DEFAULT_TOMCAT_CONFIGURATION.getResourcePath());
            if (!webContentFolder.exists()) {
                webContentFolder = Files.createTempDirectory("default-doc-base").toFile();
            }

            log.info("Tomcat:configuring app with basedir: [{}]", webContentFolder.getAbsolutePath());
            StandardContext ctx = (StandardContext) tomcat.addWebapp(DEFAULT_TOMCAT_CONFIGURATION.getContextPath(), webContentFolder.getAbsolutePath());
            ctx.setParentClassLoader(this.getClass().getClassLoader());

            WebResourceRoot resources = new StandardRoot(ctx);
            ctx.setResources(resources);
            // 添加 jspServlet，defaultServlet 和自己实现的 dispatcherServlet

            /**
             * defaultServlet用于处理静态资源如 css、js 文件
             * jspServlet用于处理 jsp
             * 这2个类其实在tomcat的web.xml中也配置了
             */
            tomcat.addServlet("", "jspServlet", new JspServlet()).setLoadOnStartup(3);
            tomcat.addServlet("", "defaultServlet", new DefaultServlet()).setLoadOnStartup(1);


            tomcat.addServlet("", "dispatcherServlet", new DispatcherServlet()).setLoadOnStartup(0);
            ctx.addServletMappingDecoded("/templates/" + "*", "jspServlet");
            ctx.addServletMappingDecoded("/static/" + "*", "defaultServlet");
            ctx.addServletMappingDecoded("/*", "dispatcherServlet");
        } catch (Exception e) {
            log.error("初始化 Tomcat 失败", e);
            throw new RuntimeException(e);
        }
    }


    @Override
    protected void serverStart() {
        try {
            tomcat.start();
            String address = tomcat.getServer().getAddress();
            int port = tomcat.getConnector().getPort();
            log.info("address: http://{}:{}", address, port);
            tomcat.getServer().await();
        } catch (LifecycleException e) {
            log.error("启动 Tomcat 失败", e);

        }


    }

    @Override
    public void stop() {
        try {
            tomcat.stop();
        } catch (LifecycleException e) {
            log.error("关闭 Tomcat 失败，强制退出虚拟机", e);
        } finally {
            System.exit(-1);

        }
    }


    /**
     * getRootFolder()方法中获取的是当前项目目录下的 target 文件夹，
     * 即 idea 默认的编译文件保存的位置，如果修改了编译文件保存位置，这里也要修改。
     *
     * @return
     */
    private File getRootFolder() {
        try {
            File root;
            String runningJarPath = this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath().replaceAll("\\\\", "/");
            int lastIndexOf = runningJarPath.lastIndexOf("/target/");
            if (lastIndexOf < 0) {
                root = new File("");
            } else {
                root = new File(runningJarPath.substring(0, lastIndexOf));
            }
            log.info("Tomcat:application resolved root folder: [{}]", root.getAbsolutePath());
            return root;
        } catch (URISyntaxException ex) {
            throw new RuntimeException(ex);
        }
    }
}
